The missile is composed of two sprites, the first is static, and the other one is animated (missile flame), so the object studied is what I called a
"composite object", because it uses more than one memory slot on the object segment in RAM, each slot is dedicated to a sprite ! The subsprite 2
is composed of two sprites, displayed one after another, generating an "animation". Most objects of the game are composite (bosses used a lot of memory slots,
that's why enemies are deleted from object segment when a boss is loaded).
To correctly understand the asm code, you need object slot information :
| OBJECT SLOT OFFSET/VARIABLE INFORMATION |
| 0x00 STATUS BITFIELD (if zero, object deleted) 0x02 ID 0x04 HP 0x06 SCORE EARNED ? 0x0E NB OF UNITS (more than 1 if COMPOSITE) 0x10 LIFE COUNTER (fast incrementation during all the object life) (used as a seed value for displaying animations) 0x12 LIFE COUNTER 2 ? 0x14 X Position 0x16 Y POsition 0x18 X Velocity ? 0x1A Y Velocity ? 0x20 SCREEN Y POS 0x24 SPRITE PATTERN USED TO DISPLAY THE SPRITE (composed of a sprite number/offset in the lvl bank and some flags used for the sprite orientation) 0x26 SCREEN X POS 0x2E ADRESS OF NEXT SLOT (if composite) 0x50 (byte) -> when object destroyed, routine counter for mObj (execute specific code when object deleted) 0x5C ROUTINE NUMBER 0x5E ROUTINE TIME COUNTER An object slot has a length of 0x60 bytes, most variables usage depends on the object program, that's why a lot of variables offsets are undocumented. |
ROM:000097B8 Obj1F: ; GORGON BIG MISSILE
ROM:000097B8 move.w #$62E8,d0 ; subsprite2:1 offset 0x62E8
ROM:000097BC andi.w #1,$10(a6) ; the 0x10 variable of the memory slot contains the life counter
ROM:000097C2 beq.s Obj1F_97C8 ; a andi operation is done to generate a choice between displaying subsprite2:1 and 2:2
; which depends on the bit 0 of the 0x10 variable
; because this variable is incremented by another part of the game's code
; tests on digits are done to generate animation, digit chosen corresponds to the speed
ROM:000097C4 move.w #$62F0,d0 ; subsprite2:2 offset 0x62F0
ROM:000097C8
ROM:000097C8 Obj1F_97C8: ; CODE XREF: ROM:000097C2j
ROM:000097C8 addq.w #3,$18(a6)
ROM:000097CC move.w $18(a6),d1 ; getting velocity
ROM:000097D0 move.w $20(a6),d2
ROM:000097D4 move.w #$62E0,$24(a6)
ROM:000097DA tst.w $28(a6) ; orientation of the missile (to the left or to the right ?)
ROM:000097DE bne.s Obj1F_980C (MISSILE RIGHT ORIENTATION)
; MISSILE LEFT ORIENTATION
ROM:000097E0 sub.w d1,$14(a6) ; decreasing x position
ROM:000097E4 move.w $14(a6),d1 ; saving x position
ROM:000097E8 asr.w #5,d1
ROM:000097EA move.w d1,$26(a6)
ROM:000097EE cmp.w #$40,d1 ; '@' ; if d1 (x position) is out of screen (on left)
ROM:000097F2 bcs.w DeleteObject ; object must be deleted
ROM:000097F6 movea.w $2E(a6),a5 ; getting next slot adress in a5
ROM:000097FA addi.w #$20,d1 ; ' ' ; updating values on the next slot
ROM:000097FE move.w d2,$20(a5)
ROM:00009802 move.w d1,$26(a5)
ROM:00009806 move.w d0,$24(a5) ; saving the good sprite to display on the subsprite2
ROM:0000980A rts ; END
ROM:0000980C ; ---------------------------------------------------------------------------
ROM:0000980C
; MISSILE RIGHT ORIENTATION
ROM:0000980C Obj1F_980C: ; CODE XREF: ROM:000097DEj
ROM:0000980C add.w d1,$14(a6) ; increasing x position
ROM:00009810 move.w $14(a6),d1 ; saving x position
ROM:00009814 asr.w #5,d1
ROM:00009816 move.w d1,$26(a6) ; saving x screen pos ?
ROM:0000981A bset #3,$24(a6)
ROM:00009820 cmp.w #$1E0,d1 ; if x position out of screen (on right)
ROM:00009824 bcc.w DeleteObject ; object must be deleted
ROM:00009828 movea.w $2E(a6),a5 ; getting next slot adress in a5 (subsprite 2)
ROM:0000982C subi.w #$20,d1 ; ' ' ; updating values on the next slot
ROM:00009830 move.w d2,$20(a5)
ROM:00009834 move.w d1,$26(a5)
ROM:00009838 bset #$B,d0 ; setting orientation of the sprite
ROM:0000983C move.w d0,$24(a5) ; saving the good sprite to display on the subsprite2
ROM:00009840 rts ; END
This object is a really simple one, most objects are bigger than this one, composed of some routines.
By using IDA, we can simplify object programs, by creating enumerations on RAM Variables, so the
move.w d1, $26(a6)
could be
move.w d1, X_Screen(a6)
I didn't do that on my disassembly, if you want some powerful ASM Hacking, you should rewrite the game's code by introducting
IDA's enums on RAM variables (renaming RAM adresses), and on offsets on object slots. It's a long work which can be automated by
some IDA scripts.